/*
 * Copyright (C) 2020 Graylog, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the Server Side Public License, version 1,
 * as published by MongoDB, Inc.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * Server Side Public License for more details.
 *
 * You should have received a copy of the Server Side Public License
 * along with this program. If not, see
 * <http://www.mongodb.com/licensing/server-side-public-license>.
 */
import React from 'react';
import { render, screen } from 'wrappedTestingLibrary';

import type { FeedItem } from 'components/content-stream/hook/useContentStream';
import mockComponent from 'helpers/mocking/MockComponent';
import ContentStreamNews from 'components/content-stream/ContentStreamNews';
import { asMock } from 'helpers/mocking';
import useContentStream from 'components/content-stream/hook/useContentStream';

jest.mock('components/common/Carousel/Carousel', () => mockComponent('MockCarousel'));

jest.mock('components/content-stream/news/ContentStreamNewsItem', () => ({ feed }: { feed: FeedItem }) => (
  <div>{feed.title}</div>
));

const useContentMock = {
  feedList: [
    {
      title: 'Getting Started with GROK Patterns',
      link: 'https://graylog.org/post/getting-started-with-grok-patterns/',
      comments: 'https://graylog.org/post/getting-started-with-grok-patterns/?noamp=mobile#respond',
      'dc:creator': 'The Graylog Team',
      pubDate: 'Thu, 27 Jul 2023 18:30:07 +0000',
      category: ['Log Management & Analytics', 'In Product'],
      guid: {
        '#text': 'https://graylog.org/?p=16241',
        attr_isPermaLink: 'false',
      },
      description:
        '<p>If you’re new to logging, you might be tempted to collect all the data you possibly can. More information means more insights; at least, those NBC “the more you know” public services announcements told you it would help. Unfortunately, you can create new problems if you do too much logging. To streamline your log collection, [&#8230;]</p>\n<p>The post <a rel="nofollow" href="https://graylog.org/post/getting-started-with-grok-patterns/">Getting Started with GROK Patterns</a> appeared first on <a rel="nofollow" href="https://graylog.org">Graylog</a>.</p>\n',
      'content:encoded':
        '<p>If you’re new to logging, you might be tempted to collect all the data you possibly can. More information means more insights; at least, those NBC “the more you know” public services announcements told you it would help. Unfortunately, you can create new problems if you do too much logging. To <a href="https://www.graylog.org/post/achieve-more-streamlining-your-logs/">streamline your log collection</a>, you can apply some filtering of messages directly from the log source. However, to parse the data, you may need to use a Grok pattern.</p>\n<p>&nbsp;</p>\n<p>If you’re just getting started with Grok patterns, you might want to know what they are, how they work, and how to use them.</p>\n<h2>What is Grok?</h2>\n<p>Used for parsing and analyzing log data, Grok is a tool in the Elasticsearch, Logstash, and Kibana (ELK) stack that helps extract structured data from unstructured log messages. Grok uses regular expressions or pattern matching  to define pattern definitions, enabling users to separate log message fields to more easily analyze the data.</p>\n<p>&nbsp;</p>\n<p>With Grok, users can define patterns to match any type of log message data, including:</p>\n<ul>\n<li>Email addresses</li>\n<li>IP addresses</li>\n<li>Positive and negative integers</li>\n<li>Sets of characters</li>\n</ul>\n<p>&nbsp;</p>\n<p>Grok has a regular expression library and built-in patterns to make getting started easier. However, users can also create pattern files and add more patterns. With the filter plugins, users can apply patterns to log data in a configuration file.</p>\n<p>&nbsp;</p>\n<p>Grok patterns follow the Elastic Common Schema (ECS), enabling users to normalize event data at ingest time to make querying the data sources easier. Grok is particularly effective with log formats written for human rather than computers, like:</p>\n<ul>\n<li>Syslog logs</li>\n<li>Apache and other web server logs</li>\n<li>Mysql log</li>\n</ul>\n<h2>How does it work?</h2>\n<p>Grok patterns use regular expressions to match patterns in log messages. When the Grok filter finds a match, it separates the matched data into fields.</p>\n<h3>Regular expressions (regex)</h3>\n<p>Regex consists of a character sequence that defines a search pattern, enabling complex search and replace operations. The process works similarly to the “Find and Replace With” functions in Word and Google Docs.</p>\n<p>&nbsp;</p>\n<p>You should also keep in mind that regular expressions:</p>\n<ul>\n<li>Use a syntax of specific characters and symbols to define a pattern</li>\n<li>Can match patterns in strings, making them useful for processing and filtering large amounts of data</li>\n<li>Can replace parts of a string that match a pattern for advanced manipulation and editing</li>\n</ul>\n<p>&nbsp;</p>\n<p>Programming languages that use regular expressions, like Grok patterns, provide built-in libraries.</p>\n<h3>Grok basics</h3>\n<p>The fundamentals of parsing log messages with Grok patterns are:</p>\n<ul>\n<li><strong>Defining patterns</strong>: using regex syntax for predefined or custom patterns that include alphanumeric characters, sets of characters, single characters, or utf-8 characters</li>\n<li><strong>Matching patterns</strong>: using filter plugins to match and extract pattern-defined relevant fields from log messages</li>\n<li><strong>Pattern files</strong>: adding predefined or custom patterns to files for sharing across multiple projects or teams</li>\n<li><strong>Composite patterns</strong>: combining multiple predefined or custom patterns into a single pattern for more complex log parsing that simplifies the parsing process and reduces the overall number of partners needed</li>\n</ul>\n<p>&nbsp;</p>\n<h2>Using Grok patterns</h2>\n<p>Grok patterns are essential to processing and analyzing log data because they enable you to extract and categorize data fields within each message. Parsing data is the first step toward normalizing it which is ultimately how you can correlate events across your environment.</p>\n<h3>Normalizing diverse log data formats</h3>\n<p>Log data comes in various formats, including:</p>\n<ul>\n<li>CSV</li>\n<li>JSON</li>\n<li>XML</li>\n</ul>\n<p>&nbsp;</p>\n<p>Further, you need visibility into diverse log types, including:</p>\n<ul>\n<li>Access logs</li>\n<li>System logs</li>\n<li>Application logs</li>\n<li>Security logs</li>\n</ul>\n<p>&nbsp;</p>\n<p>With Grok patterns, you can parse these logs, extracting the defined fields no matter where it’s contained in the technology-generated format. Since you’re focusing on the type of information rather than the message itself, you can now correlate and analyze the data.</p>\n<h3>Debugging Grok expressions</h3>\n<p>Getting the regular expressions for parsing the log files can be challenging. For example, the username could be represented as either:</p>\n<ul>\n<li>USERNAME [a-zA-Z0-9._-]+</li>\n</ul>\n<p>or</p>\n<ul>\n<li>USER %{USERNAME}</li>\n</ul>\n<p>&nbsp;</p>\n<p>Debugging Grok expressions can be a little bit of trial and error, as you compare your expressions to the log files you want to parse.</p>\n<p>&nbsp;</p>\n<p>However, you can find online applications to help you construct a regular expression that matches your given log lines. Some examples of these tools include:</p>\n<ul>\n<li><strong>Incremental construction</strong>: prompting you to select common prefixes or Grok library patterns then running the segment against the log lines</li>\n<li><strong>Matcher</strong>: testing Grok expressions against several log lines simultaneously to determine matches and highlighting unmatched data</li>\n<li><strong>Automatic construction</strong>: running Grok expressions against log lines to generate options</li>\n</ul>\n<p>&nbsp;</p>\n<h3>Managing log data that doesn’t fit a defined pattern</h3>\n<p>Not every log message will have data that fits the defined pattern. Grok manages this in a few different ways:</p>\n<ul>\n<li>Ignoring lines in log data outside the defined pattern to filter out irrelevant or corrupted entries</li>\n<li>Adding custom tags to unmatched entries to identify and track issues with log data or categories entries based on custom criteria</li>\n<li>Using a separate log file or database table for further analyzing or troubleshooting log data</li>\n<li>Creating fallback patterns that apply when the initial pattern fails to match the entry for handling more complex log data</li>\n</ul>\n<p>&nbsp;</p>\n<h2>Graylog: Parsing Made Simple</h2>\n<p>With Graylog, you can use Grok patterns with both extractors and processing pipelines. However, our <a href="https://go2docs.graylog.org/5-0/what_more_can_graylog_do_for_me/security_content_packs.html?tocpath=What%20More%20Can%20Graylog%20Do%20for%20Me%253F%7CGraylog%20Illuminate%7CSecurity%20Content%20Packs%7C_____0">Graylog Illuminate</a> content is included with both <a href="https://www.graylog.org/products/security/">Graylog Security</a> and <a href="https://www.graylog.org/products/operations/">Graylog Operations</a>, enabling you to automate the parsing process without having to build your own Grok patterns. <a href="https://www.graylog.org/features/sidecar/">Graylog Sidecar</a> enables you to gather logs from all your computer systems with any log collection agent while centralized, mass deployment of sidecars can support multiple configurations per collector.</p>\n<p>&nbsp;</p>\n<p>With Graylog Operations and Graylog Security, you can use pre-built content, including parsing rules and pipelines, that help you get immediate value from your log data. You also gain access to search templates, dashboards, correlated alerts, reports, dynamic lookup tables, and streams that give you visibility into your environment. By leveraging our lightning-fast search capabilities, you can get the answers you need as soon as you need them to get to the root cause of incidents as quickly as possible.</p>\n<p>&nbsp;</p>\n<p>To learn more about how Graylog can help you gain the full value of your log data, <a href="https://www.graylog.org/contact-us/">contact us today.</a></p>\n<p>The post <a rel="nofollow" href="https://graylog.org/post/getting-started-with-grok-patterns/">Getting Started with GROK Patterns</a> appeared first on <a rel="nofollow" href="https://graylog.org">Graylog</a>.</p>\n',
      'wfw:commentRss': 'https://graylog.org/post/getting-started-with-grok-patterns/feed/',
      'slash:comments': 0,
      'media:content': {
        'media:title': {
          '#text': '0723_Getting Started with Grok Patterns',
          attr_type: 'plain',
        },
        'media:thumbnail': {
          attr_url:
            'https://graylog.org/wp-content/uploads/2023/07/0723_Getting-Started-with-Grok-Patterns-150x150.jpg',
          attr_width: '150',
          attr_height: '150',
        },
        'media:copyright': 'Jeff Darrington',
        attr_url: 'https://graylog.org/wp-content/uploads/2023/07/0723_Getting-Started-with-Grok-Patterns.jpg',
        attr_type: 'image/jpeg',
        attr_medium: 'image',
        attr_width: '1200',
        attr_height: '628',
      },
    },
    {
      title: 'Getting Your Logs In Order: A Guide to Normalizing with Graylog',
      link: 'https://graylog.org/post/getting-your-logs-in-order-a-guide-to-normalizing-with-graylog/',
      comments:
        'https://graylog.org/post/getting-your-logs-in-order-a-guide-to-normalizing-with-graylog/?noamp=mobile#respond',
      'dc:creator': 'The Graylog Team',
      pubDate: 'Fri, 16 Jun 2023 20:16:42 +0000',
      category: ['Graylog Labs', 'GraylogLabs', 'In Product'],
      guid: {
        '#text': 'https://www.graylog.org/?p=15645',
        attr_isPermaLink: 'false',
      },
      description:
        '<p>If you work with large amounts of log data, you know how challenging it can be to analyze that data and extract meaningful insights. One way to make log analysis easier is to normalize your log messages. In this post, we&#8217;ll explain why log message normalization is important and how to do it in Graylog. [&#8230;]</p>\n<p>The post <a rel="nofollow" href="https://graylog.org/post/getting-your-logs-in-order-a-guide-to-normalizing-with-graylog/">Getting Your Logs In Order: A Guide to Normalizing with Graylog</a> appeared first on <a rel="nofollow" href="https://graylog.org">Graylog</a>.</p>\n',
      'content:encoded':
        '<p>If you work with large amounts of log data, you know how challenging it can be to analyze that data and extract meaningful insights. One way to make log analysis easier is to normalize your log messages. In this post, we&#8217;ll explain why log message normalization is important and how to do it in Graylog.</p>\n<h2>Why is log message normalization important?</h2>\n<p>When log messages are generated by different systems or applications, they often have different formats and structures. For example, one application might log the date and time in a different format than another application, or it might use different names for the same field.</p>\n<p>This can make it difficult to analyze log data and extract insights. Normalizing log messages involves transforming them into a consistent format that makes it easier to analyze and compare data across different systems and applications.</p>\n<p>By normalizing log messages, you can:</p>\n<ul>\n<li>Improve searchability: When log messages are normalized, it&#8217;s easier to search for specific fields or values across different log sources.</li>\n<li>Increase efficiency: Normalized log messages are easier to parse and analyze, which can save time and resources.</li>\n<li>Reduce errors: When log messages are normalized, it&#8217;s less likely that errors will occur during log analysis due to inconsistencies in data formats.</li>\n</ul>\n<p>&nbsp;</p>\n<h2>How to normalize log messages in Graylog</h2>\n<h3>Step 1: Define the log message format</h3>\n<p>The first step in normalizing log messages is to define the format of the log messages you want to normalize. This will involve identifying the fields in the log messages that are relevant for your use case.</p>\n<p>For example, you might want to extract:</p>\n<ul>\n<li>date and time</li>\n<li>log level</li>\n<li>source IP address</li>\n<li>message text from each log message</li>\n</ul>\n<p>&nbsp;</p>\n<p>The Graylog team has defined a format, or schema, for log messages called the Graylog Information Model &#8211; https://schema.graylog.org/en/stable/ . At Graylog, we would recommend using this schema for your logs as all of the Dashboards, Event Definition and other content we provide under the Illuminate umbrella conforms to this model.</p>\n<h3>Optional &#8211; Step 2: Create a Grok pattern</h3>\n<p>Once you have defined the log message format, if the logs are currently not parsed, the next step is to create a Grok pattern. Grok is a powerful tool for parsing unstructured log data into structured data that can be easily analyzed. To create a Grok pattern, you will need to use regular expressions to extract the relevant data fields from your log messages.</p>\n<p>Graylog provides a Grok Debugger that you can use to test your <a href="https://go2docs.graylog.org/5-1/making_sense_of_your_log_data/functions_descriptions.html?Highlight=grok">Grok patterns</a>. This can help you ensure that your patterns are accurate and that they correctly extract the relevant data fields from your log messages.</p>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15646" src="https://www.graylog.org/wp-content/uploads/2023/06/Picture1-4.png" alt="" width="478" height="425" /></p>\n<h3>Step 3: Create a message processing pipeline</h3>\n<p>The next step is to create a message processing pipeline. A message processing pipeline is a set of rules that defines how your log messages are processed.</p>\n<p>To create a pipeline in Graylog, go to:</p>\n<ul>\n<li>System -> Pipelines and click on &#8220;Create pipeline&#8221;</li>\n<li>Give your pipeline a name and a description</li>\n<li>define the rules that will be applied to your log messages.</li>\n</ul>\n<p>&nbsp;</p>\n<h4>Field extraction with Grok</h4>\n<p>If your messages are not parsed at all, you will want to create a rule that uses your Grok pattern to extract the relevant data fields from your log messages. The pipeline rule function grok should be used here:</p>\n<pre><code>grok(pattern: string, value: string, [only_named_captures: <strong>boolean</strong>])</code></pre>\n<h4>Renaming existing fields</h4>\n<p>If your messages are already being parsed by another mechanism, you can rename the fields to conform to your newly defined log schema. Graylog provides an easy to use pipeline function to perform this action:</p>\n<pre><code>rename_field(old_field: <strong>string</strong>, new_field: <strong>string</strong>, [<strong>message</strong>: <strong>Message</strong>])</code></pre>\n<h3>Step 4: Verify your results</h3>\n<p>After you have applied your pipeline to your streams, you should start seeing normalized log messages in Graylog. To verify that your log messages are being normalized correctly, you can use Graylog&#8217;s search functionality to search for specific fields in your log messages.</p>\n<h2>Conclusion</h2>\n<p>Log message normalization is an essential step in analyzing large amounts of log data. Normalizing log messages involves transforming them into a consistent format, making it easier to analyze and compare data across different systems and applications. Graylog provides a set of tools for normalizing log messages, including defining log message formats, creating Grok patterns, and building message processing pipelines. By normalizing log messages, organizations can improve searchability, increase efficiency, and reduce errors during log analysis. By following the steps outlined in this article, organizations can better manage their log data and extract meaningful insights from it.</p>\n<p>The post <a rel="nofollow" href="https://graylog.org/post/getting-your-logs-in-order-a-guide-to-normalizing-with-graylog/">Getting Your Logs In Order: A Guide to Normalizing with Graylog</a> appeared first on <a rel="nofollow" href="https://graylog.org">Graylog</a>.</p>\n',
      'wfw:commentRss': 'https://graylog.org/post/getting-your-logs-in-order-a-guide-to-normalizing-with-graylog/feed/',
      'slash:comments': 0,
      'media:content': {
        'media:title': {
          '#text': 'Logs In Order',
          attr_type: 'plain',
        },
        'media:thumbnail': {
          attr_url: 'https://graylog.org/wp-content/uploads/2023/06/Logs-N-Order.jpg',
          attr_width: '150',
          attr_height: '79',
        },
        'media:description': {
          '#text': 'Logs In Order',
          attr_type: 'plain',
        },
        'media:copyright': 'Jeff Darrington',
        attr_url: 'https://graylog.org/wp-content/uploads/2023/06/Logs-N-Order.jpg',
        attr_type: 'image/jpeg',
        attr_medium: 'image',
        attr_width: '1200',
        attr_height: '628',
      },
    },
    {
      title: 'Case Study: Building an Operations Dashboard',
      link: 'https://graylog.org/post/building-an-operations-dashboard/',
      comments: 'https://graylog.org/post/building-an-operations-dashboard/?noamp=mobile#respond',
      'dc:creator': 'The Graylog Team',
      pubDate: 'Thu, 08 Jun 2023 20:02:25 +0000',
      category: ['Graylog Labs', 'ITOPS - DevOPS', 'Uncategorized', 'In Product', 'ITOPS', 'load balancer'],
      guid: {
        '#text': 'https://www.graylog.org/?p=15522',
        attr_isPermaLink: 'false',
      },
      description:
        '<p>Picture a simple E-commerce platform with the following components, each generating logs and metrics. Imagine now the on-call Engineer responsible for this platform, feet up on a Sunday morning watching The Lord of The Rings with a coffee, when suddenly the on-call phone starts to ring! &#160; Oh no! It’s a customer phoning, and they report [&#8230;]</p>\n<p>The post <a rel="nofollow" href="https://graylog.org/post/building-an-operations-dashboard/">Case Study: Building an Operations Dashboard</a> appeared first on <a rel="nofollow" href="https://graylog.org">Graylog</a>.</p>\n',
      'content:encoded':
        '<p>Picture a simple E-commerce platform with the following components, each generating logs and metrics. Imagine now the on-call Engineer responsible for this platform, feet up on a Sunday morning watching The Lord of The Rings with a coffee, when suddenly the on-call phone starts to ring!</p>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15543" src="https://www.graylog.org/wp-content/uploads/2023/06/1a7372c4-9d8b-4041-93fc-a001b1933432.png" alt="" width="800" height="327" /></p>\n<p>&nbsp;</p>\n<p>Oh no!</p>\n<p>It’s a customer phoning, and they report that sometimes, maybe a tenth of the time, the web front end is returning a generic error as they try to complete a workflow. The on-call engineer must open their laptop, connect to the VPN and through one interface or another and seek to build a picture of what is happening.</p>\n<h2 data-renderer-start-pos="623"><strong data-renderer-mark="true">But where to look first?</strong></h2>\n<ul class="ak-ul" data-indent-level="1">\n<li>\n<p data-renderer-start-pos="652">The Load Balancer logs, looking for strange traffic?</p>\n</li>\n<li>\n<p data-renderer-start-pos="708">The Web Server logs, looking for 50X status codes? Which requests are affected?</p>\n</li>\n<li>\n<p data-renderer-start-pos="791">The App Server logs, looking for errors? Which ones are relevant to this problem?</p>\n</li>\n<li>\n<p data-renderer-start-pos="876"><span id="7c9050cb-b750-4fb7-965e-e87887a641e0" class="inline-highlight first-mark-highlight last-mark-highlight" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="7c9050cb-b750-4fb7-965e-e87887a641e0">Performance metrics, looking for a resource bottleneck?</span></p>\n</li>\n</ul>\n<p>&nbsp;</p>\n<p data-renderer-start-pos="935">Spoiler: we hope you will not be too shocked to discover that the correct answer is a <strong data-renderer-mark="true">Graylog Operations Dashboard</strong></p>\n<p data-renderer-start-pos="935">Here is a log file from the platform:</p>\n<p data-renderer-start-pos="935"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15544" src="https://www.graylog.org/wp-content/uploads/2023/06/23450ba5-7d5e-47e3-aaf6-4cd85700b5a6.png" alt="" width="800" height="562" /></p>\n<p data-renderer-start-pos="935">There are 14 such log files being actively written, logging a total of around 380,000 events daily. Reading the log files directly like this is slow going even with the search tools of modern text editors. Working like this, it is difficult to figure out even basic facts such as when an issue started, which types of workflow are affected or even which part of the infrastructure an error is originating from. There can be thousands of different error events in a log, many benign and regularly occurring long before the issue was reported. In the circumstances, a notepad search through a few log files for “error” is not going to cut the mustard.</p>\n<h2><strong data-renderer-mark="true">OK &#8211; How can we make better sense of all these disparate indicators, using Graylog?</strong></h2>\n<p data-renderer-start-pos="935">At the most basic level, if we pull all the logs from this architecture into Graylog using collectors, we can search for key terms like “ERROR” across all the different log types at once and review the results on a timeline.</p>\n<p data-renderer-start-pos="935"><img decoding="async" loading="lazy" class="aligncenter wp-image-15545 size-full" src="https://www.graylog.org/wp-content/uploads/2023/06/1fa08211-c46c-4305-967d-a3bcbfade789.png" alt="" width="800" height="617" /></p>\n<p data-renderer-start-pos="2067">This is a useful capability, but we can do better &#8211; it’s dashboard time!</p>\n<h2 id="Designing-an-Operations-Dashboard" data-renderer-start-pos="2142">Designing an Operations Dashboard</h2>\n<p data-renderer-start-pos="2177">When designing an Operations Dashboard for a specific platform like this, we follow these broad principles:</p>\n<ul class="ak-ul" data-indent-level="1">\n<li>\n<p data-renderer-start-pos="2290">Try to get every metric you might want to view onto a single board for easy comparisons.</p>\n</li>\n<li>\n<p data-renderer-start-pos="2382">Start with the highest-level metric of uptime/success at the top, and then drill downwards.</p>\n</li>\n<li>\n<p data-renderer-start-pos="2477">Unless we are measuring overall activity, we don’t graph anything except for evidence of problem(s).</p>\n</li>\n<li>\n<p data-renderer-start-pos="2581">Metrics that are not positioned in time are not useful &#8211; <strong data-renderer-mark="true">when</strong> is as important as <strong data-renderer-mark="true">what</strong>.</p>\n</li>\n<li>\n<p data-renderer-start-pos="2671">Simple string searches (“Error”, “timeout”) are useful high level tools, but grouping the results in turn by application, server and type is what makes log aggregation <em data-renderer-mark="true">awesome</em>.</p>\n</li>\n<li>\n<p data-renderer-start-pos="2851">Follow up visualizations with data tables that contain the data shown, for easy save-to-clipboard and drill-down.</p>\n</li>\n</ul>\n<p data-renderer-start-pos="2968">Now, lets make some graphs!</p>\n<h3 id="Count-the-highest-level-metrics-of-“Activity”.[hardBreak]" data-renderer-start-pos="2998">Count the highest level metrics of “Activity”</h3>\n<ul class="ak-ul" data-indent-level="1">\n<li>\n<p data-renderer-start-pos="3049">Having a basic indication of how much activity is occurring is crucial.</p>\n</li>\n<li>\n<p data-renderer-start-pos="3124">Can tell you if there has been a massive surge of work, or else if your applications abruptly went idle.</p>\n</li>\n<li>\n<p data-renderer-start-pos="3232">Starting at the highest level, we first count requests to the load balancer, sorted by request.</p>\n</li>\n</ul>\n<p>&nbsp;</p>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15546" src="https://www.graylog.org/wp-content/uploads/2023/06/5d1777c0-06b4-4413-8345-5897eb28d33c.png" alt="" width="800" height="308" /></p>\n<pre><code>Row: timestamp\nColumn: request\nMetric: count()\nType: Bar Chart\nMode: Relative</code></pre>\n<p data-renderer-start-pos="3417">This is useful, but to understand health we need to see the traffic that is “failing”:</p>\n<h3 id="Parse-the-Load-Balancer-or-Firewall-logs-to-view-traffic." data-renderer-start-pos="3506">Parse the Load Balancer or Firewall logs to view traffic</h3>\n<p>When monitoring a system that has a web interface like this one, a good high-level metric to track is how many API requests are returning with erroneous 40X or 50X HTTP status codes.</p>\n<p>To make that distinction here, there is a requirement that we parse several fields out of our load balancer or firewall logs (as applicable).</p>\n<p>For example, lets parse the AWS Load-balancer log for the following fields.</p>\n<ol class="ak-ol" data-indent-level="1">\n<li>\n<p data-renderer-start-pos="3973"><span style="color: #800080;"><strong data-renderer-mark="true"><span class="fabric-text-color-mark" data-renderer-mark="true" data-text-custom-color="#403294"><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9"> client </span></span></strong></span></p>\n</li>\n<li>\n<p data-renderer-start-pos="3985"><strong data-renderer-mark="true"><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9"> </span><span class="fabric-text-color-mark" style="color: #ff0000;" data-renderer-mark="true" data-text-custom-color="#bf2600"><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9">target_processing_time </span></span></strong></p>\n</li>\n<li>\n<p data-renderer-start-pos="4013"><span style="color: #ffcc00;"><strong data-renderer-mark="true"><span class="fabric-text-color-mark" data-renderer-mark="true" data-text-custom-color="#ffc400"><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9"> elb_status_code</span></span></strong></span></p>\n</li>\n<li>\n<p data-renderer-start-pos="4033"><span style="color: #339966;"><strong data-renderer-mark="true"><span class="fabric-text-color-mark" data-renderer-mark="true" data-text-custom-color="#006644"><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9"> request </span></span></strong></span></p>\n</li>\n</ol>\n<p data-renderer-start-pos="4047"><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9">h2 2023-03-07T16:44:37.258775Z app/tf-lb-2022030713390888170000000a/25n7251d3ee489422 </span><span style="color: #800080;"><strong data-renderer-mark="true"><span class="fabric-text-color-mark" data-renderer-mark="true" data-text-custom-color="#403294"><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9">111.222.11.55:43331</span></span></strong></span><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9"> 11.78.166.66:6200 0.000 </span><span style="color: #ff0000;"><strong data-renderer-mark="true"><span class="fabric-text-color-mark" data-renderer-mark="true" data-text-custom-color="#bf2600"><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9">0.015</span></span></strong></span><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9"> 0.000 </span><span style="color: #ffcc00;"><strong data-renderer-mark="true"><span class="fabric-text-color-mark" data-renderer-mark="true" data-text-custom-color="#ffc400"><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9">200</span></span></strong></span><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9"> 200 38 489 &#8220;</span><span style="color: #339966;"><strong data-renderer-mark="true"><span class="fabric-text-color-mark" data-renderer-mark="true" data-text-custom-color="#006644"><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9">GET https://dingovision:443/api/system/basket/checkout/1.0</span></span></strong></span><span id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9" data-renderer-mark="true" data-mark-type="annotation" data-mark-annotation-type="inlineComment" data-id="a4a33bf6-46b8-4905-835e-d0bbcffafbc9">&#8221; &#8220;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/111.0&#8221; QQQHE-QSA-QQQQ28-GQ-SHA256 TLSv1.2 arn:aws:elasticloadbalancing:us-east-1:2513411:targetgroup/tf-20220308165834754600000001/ce33332a240c0c &#8220;Root=1-33f22ff-1de6aa423523490545375926&#8221; &#8220;dingoshipping.net&#8221; &#8220;arn:aws:acm:us-east-1:2513411:certificate/6663QQ-a8ad-7766BB332&#8221; 0 2023-03-07T16:44:37.243000Z &#8220;forward&#8221; &#8220;-&#8221; &#8220;-&#8221; &#8220;11.78.166.66.6200&#8221; &#8220;200&#8221; &#8220;-&#8221; &#8220;-&#8220;</span></p>\n<p data-renderer-start-pos="4702">We can use a Pipeline rule to extract the fields we need using grok:</p>\n<pre><code>rule "parse AWS LB log"\nwhen\n  true\nthen\n  let x = to_string($message.message);\n  let parsed = grok(pattern: "%{NOTSPACE:request_type} %{NOTSPACE:log_timestamp:datetime} %{NOTSPACE:elb} %{NOTSPACE:client:string} %{NOTSPACE:target} %{NOTSPACE:request_processing_time:float} %{NOTSPACE:target_processing_time:float} %{NOTSPACE:response_processing_time:float} %{NOTSPACE:elb_status_code} %{NOTSPACE:target_status_code} %{NOTSPACE:received_bytes:float} %{NOTSPACE:sent_bytes:float} %{QUOTEDSTRING:request} %{QUOTEDSTRING:user_agent} %{NOTSPACE:ssl_cipher} %{NOTSPACE:ssl_protocol} %{NOTSPACE:target_group_arn} %{QUOTEDSTRING:trace_id} %{QUOTEDSTRING:domain_name} %{QUOTEDSTRING:chosen_cert_arn} %{NOTSPACE:matched_rule_priority:int} %{NOTSPACE:request_creation_time} %{QUOTEDSTRING:actions_executed} %{QUOTEDSTRING:redirect_url} %{QUOTEDSTRING:error_reason} %{NOTSPACE:target_port_list} %{NOTSPACE:target_status_code_list} %{NOTSPACE:classification} %{NOTSPACE:classification_reason}",value: x);\n  set_fields(parsed);\nend</code></pre>\n<p data-renderer-start-pos="4702">This lets us…</p>\n<h2 id="Count-Your-Load-Balancer-Error-Status-Codes-by-API-Request[hardBreak]" data-renderer-start-pos="5809">Count Your Load Balancer Error Status Codes by API Request</h2>\n<ul class="ak-ul" data-indent-level="1">\n<li>\n<p data-renderer-start-pos="5872">See how many and which API requests are failing.</p>\n</li>\n<li>\n<p data-renderer-start-pos="5924">This is useful when trying to understand a sudden spike in failed requests- for example, checking if all of those failed requests were making the same API call, or are all associated with one host.</p>\n</li>\n</ul>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15547" src="https://www.graylog.org/wp-content/uploads/2023/06/d2f1b0ef-98ff-4978-98f7-59538e253a93.png" alt="" width="800" height="578" /></p>\n<pre><code>Filter: _exists_:elb_status_code AND NOT elb_status_code:20?\nRow: timestamp\nColumn: client\nMetric: count()\nType: Bar Chart\nMode: Relative</code></pre>\n<pre><code>Filter: _exists_:elb_status_code\nRow: timestamp\nColumn: elb_status_code\nMetric: count()\nType: Bar Chart\nMode: Relative</code></pre>\n<p data-renderer-start-pos="6388">This draws us a fairly clear picture of <strong data-renderer-mark="true">what</strong> is failing. Now we need to figure out <strong data-renderer-mark="true">why</strong> it is failing.</p>\n<h2 id="Track-the-processing-time-of-API-Calls[hardBreak]" data-renderer-start-pos="6493">Track the processing time of API Calls</h2>\n<ul class="ak-ul" data-indent-level="1">\n<li>\n<p data-renderer-start-pos="6536">Before delving the application logs looking for errors, we can easily check for performance problems by inspecting how long API requests are taking to process.</p>\n</li>\n<li>\n<p data-renderer-start-pos="6699">The sum of target processing time is a good measure of work performed by the application layer and database.</p>\n</li>\n<li>\n<p data-renderer-start-pos="6812">If a particular request is associated with a large proportion of the total target processing time on your environment, either that request is happening very frequently, has poor performance, or both &#8211; a data table can inform us which.</p>\n</li>\n</ul>\n<p>&nbsp;</p>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15548" src="https://www.graylog.org/wp-content/uploads/2023/06/dec1332a-8b95-4f4b-bc82-c2cb2804db80.png" alt="" width="800" height="403" /></p>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15549" src="https://www.graylog.org/wp-content/uploads/2023/06/d1215019-46d0-4eb2-8e76-b6a82b9713b2.png" alt="" width="800" height="212" /></p>\n<p>&nbsp;</p>\n<pre><code>Filter: _exists_:elb_status_code\nRow: timestamp\nColumn: request\nMetric: sum(target_processing time)\nType: Bar Chart\nMode: Relative</code></pre>\n<pre><code>Filter: _exists_:elb_status_code\nRow: request\nMetric: sum(target_processing time)\nMetric: avg(target_processing time)\nMetric: max(target_processing time)\nMetric: count()\nType: Data Table</code></pre>\n<p>&nbsp;</p>\n<p data-renderer-start-pos="7378">So now we can understand the traffic coming in, see the failure events and spot incidents of poor performance that correlate. Now we are ready to dig into the application logs and look for errors and timeouts around these periods! <span data-emoji-id="1f31e" data-emoji-short-name=":sun_with_face:" data-emoji-text="&#x1f31e;"><span class="emoji-common-main-styles emoji-common-node emoji-common-emoji-image css-19bdfyn" title=":sun_with_face:" role="img" data-testid="image-emoji-:sun_with_face:" data-emoji-type="image" aria-label=":sun_with_face:"><img decoding="async" loading="lazy" class="emoji" src="https://graylogdocumentation.atlassian.net/gateway/api/emoji/d01c7ac8-b329-493b-915b-3a726af4cc5e/1f31e/path" alt=":sun_with_face:" width="20" height="20" data-emoji-short-name=":sun_with_face:" data-emoji-id="1f31e" data-emoji-text="&#x1f31e;" /></span></span></p>\n<h2 id="Count-Timeout-by-Source-(or-Application-Name)[hardBreak]" data-renderer-start-pos="7614">Count Timeout by Source (or Application Name)</h2>\n<ul class="ak-ul" data-indent-level="1">\n<li>\n<p data-renderer-start-pos="7664">Indicates the existence of timeouts in your log files &#8211; useful for detecting connectivity or performance problems.</p>\n</li>\n<li>\n<p data-renderer-start-pos="7783">Not all results will be erroneous (there are often benign timeouts printed to log) but a useful view when paired with others.</p>\n</li>\n</ul>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15550" src="https://www.graylog.org/wp-content/uploads/2023/06/f6bd9b05-9b2c-4360-81b0-f6d26525de88.png" alt="" width="800" height="352" /></p>\n<p><span class="">Filter: “timeout” OR “time out” OR “timed out”<br />\n</span></p>\n<pre><code>Row: timestamp\nColumn: source\nMetric: count()\nType: Bar Chart\nMode: Relative</code></pre>\n<h3 id="Count-Error-by-Application[hardBreak]" data-renderer-start-pos="8043">Count Error by Application</h3>\n<ul>\n<li data-renderer-start-pos="8043">Simple but surprisingly effective tool: just search the logs for “ERROR” and group the results by source or application name.</li>\n</ul>\n<ul class="ak-ul" data-indent-level="1">\n<li>\n<p data-renderer-start-pos="8203">Not all results will be errors (mean developers are not above printing “no error” or “errors: 0” to their application logs), and some further filtering might be required to wean out the false positives.</p>\n</li>\n</ul>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15551" src="https://www.graylog.org/wp-content/uploads/2023/06/862850a2-98a7-46e2-8b51-c988ea7623b3.png" alt="" width="800" height="255" /></p>\n<p>&nbsp;</p>\n<pre><code>Filter: “ERROR”\nRow: timestamp\nColumn: source\nMetric: count()\nType: Bar Chart\nMode: Relative</code></pre>\n<h2 id="Parse-Generic-Error-Summaries" data-renderer-start-pos="8506">Parse Generic Error Summaries</h2>\n<p data-renderer-start-pos="8506">It is useful to know <strong data-renderer-mark="true">when</strong> a lot of errors occur, as above, but often, it is far more useful to know <strong data-renderer-mark="true">which</strong> error was occurring. Aggregating errors by type is inherently a bit challenging, because there is no standard format to an error message &#8211; the text that follows the word “ERROR” tends to be all different formats, lengths and character types. Curse you, developers!</p>\n<p>Since it is not feasible to parse error descriptions neatly, we can settle instead for doing it fuzzily: after the first occurrence of “ERROR” in the message body, simply we capture the next five words separated by spaces. Those five words can then form a category, by which we can sort the errors by type.</p>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15552" src="https://www.graylog.org/wp-content/uploads/2023/06/d802fd90-b2ce-4c31-b791-39ae0aa2574b.png" alt="" width="800" height="141" /></p>\n<p>&nbsp;</p>\n<p data-renderer-start-pos="8537">For this purpose we need two Pipeline rules &#8211; one that filters out non-matches to the Regex (and instead populates the summary with a generic “Other”), and one that then uses Regex to capture the five word summary.</p>\n<pre><code>rule "short error filter"\nwhen\n  contains(value: to_string($message.message), search: "error", ignore_case: true) &&\n  regex("(?i).[E][R][R][O][R].(\\\\S+\\\\s\\\\S+\\\\s\\\\S+\\\\s\\\\S+\\\\s\\\\S+)", to_string($message.message)).matches == false \nthen\n  set_field("short_error_mssg", "Other");\nend</code></pre>\n<p>&nbsp;</p>\n<p>All messages, whether they match this Pipeline Rule or not, are then be sent to a second Pipeline stage:</p>\n<pre><code>rule "short error extract"\nwhen\n  contains(value: to_string($message.message), search: "error", ignore_case: true) &&\n  not has_field("short_error_mssg") \nthen\n  let x = regex("(?i).[E][R][R][O][R].(\\\\S+\\\\s\\\\S+\\\\s\\\\S+\\\\s\\\\S+\\\\s\\\\S+)", to_string($message.message));\n  set_field("short_error_mssg", x["0"]);\nend</code></pre>\n<p>NOTE: Regex rules should be adjusted to reflect the formatting of the logs in question.</p>\n<p>&nbsp;</p>\n<p>The Pipeline setup might look like this:</p>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15553" src="https://www.graylog.org/wp-content/uploads/2023/06/1eb3fd12-ca31-4f20-b647-c5d531462305.png" alt="" width="800" height="688" /></p>\n<p>This little trick gives us a <strong>short_error_mssg</strong> field on our messages.</p>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15554" src="https://www.graylog.org/wp-content/uploads/2023/06/994953bb-0180-4553-82f0-a0f76053f4ce.png" alt="" width="800" height="679" /></p>\n<p>&nbsp;</p>\n<p>We can use this new field to group error types together. What does that look like you ask?</p>\n<h3>Error Count by Error Type</h3>\n<ul>\n<li>Five-star deluxe view use to understand trends in application-level errors.</li>\n<li>Unusual spikes of errors are easily reviewed and correlated to the above view of “Error count by Application” to identify source.</li>\n<li>Any error identified as benign can be easily removed from this view by using a filter.</li>\n</ul>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15555" src="https://www.graylog.org/wp-content/uploads/2023/06/4143839b-f426-406d-b1ec-5c5cf892cbf7.png" alt="" width="800" height="269" /></p>\n<pre><code>Filter: _exists_:short_error_message\nRow: timestamp\nColumn: short_error_message\nMetric: count()\nType: Bar Chart\nMode: Relative</code></pre>\n<p>This is very useful &#8211; and once you spot an error here you want to know more about, you can scroll down for the…</p>\n<h3>Error Drill-down by Error Type</h3>\n<ul>\n<li>Here we delve into the message body of each error in detail. For this purpose we use a data-table.</li>\n<li>Having access to the full log message on this page in a format that can be easily read and saved to clipboard removes the need to work from multiple tabs.</li>\n</ul>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15556" src="https://www.graylog.org/wp-content/uploads/2023/06/43a3461c-fdb2-43dd-9a9a-df8e4e7a8971.png" alt="" width="800" height="365" /></p>\n<pre><code>Filter: _exists_:short_error_message\nRow: short_error_message\nMetric: count()\nMetric: latest(message)\nType: Data Table</code></pre>\n<p>We can see from the most frequent error in this table that there is an ongoing problem with Database deadlocks on a table, which is almost certainly the root cause of the interface errors the customer is reporting.</p>\n<h2>Capturing System Metrics</h2>\n<p>It can be useful to pull system metrics into Graylog to view alongside your logs. Finding a spike of errors or timeouts in an application log file makes more sense, as in this case, when you learn that the database that services the application was at 99% CPU utilization at the time!</p>\n<p>System metrics are really a whole subject of their own, but to provide a summary of where they might fit in here, it would be useful to know the CPU and Memory utilization of the database and servers that the applications are installed to.</p>\n<p>To quickly get these into Graylog, we can install MetricBeats onto each of our servers, with a configuration to send system metrics in to a Gra<span data-ref="717ba8f4-8a59-4b5c-bb37-988cced4bb2a">ylog Beats input. </span></p>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15558" src="https://www.graylog.org/wp-content/uploads/2023/06/7802cf2b-18d3-43ab-874d-61fbbd2807ec.png" alt="" width="298" height="283" /></p>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15559" src="https://www.graylog.org/wp-content/uploads/2023/06/71822291-702d-4d64-b7e3-cd15b9ca6f83.png" alt="" width="800" height="658" /></p>\n<p>This data will allow us to create some simple dashboards for tracking resource utilization across our servers, for example:</p>\n<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-15560" src="https://www.graylog.org/wp-content/uploads/2023/06/a6159bc8-a4db-445d-aaf6-7c06d5e75011.png" alt="" width="800" height="271" /></p>\n<pre><code>Filter: beats_type:metricbeat\nRow: timestamp\nColumn: source\nMetric: max(metricbeat_ststem_cpu_total_pct)\nType: Bar Chart\nMode: Relative</code></pre>\n<p>&nbsp;</p>\n<h2>Small Dashboard, Big Time Saver</h2>\n<p>That should be enough tooling to get us started!</p>\n<p>Next time that customer phones to report the web front end is returning errors, the on-call Engineer will be able to quickly dust away the Cheetos and log onto this Dashboard. With all the evidence they need one one screen, the on-call engineer can quickly scroll down to get a picture of events &#8211; no more trawling logs and system metrics across multiple interfaces while the customer gets annoyed and SLAs breach.</p>\n<p>When this incident has been resolved, as a follow up action the support team will create an alert in Graylog that triggers if this error is found in the logs again. Following best practice, the alert message will include instructions on what remedial actions the on-call Engineer should take upon receiving the alert. If this issue occurs again, the alert will facilitate a swift on-call response that can hopefully fix the problem next time before the customer even notices.</p>\n<p>We hope this little case study was illustrative of how good dashboard design can help your Operations squad be superheroes.</p>\n<p>The post <a rel="nofollow" href="https://graylog.org/post/building-an-operations-dashboard/">Case Study: Building an Operations Dashboard</a> appeared first on <a rel="nofollow" href="https://graylog.org">Graylog</a>.</p>\n',
      'wfw:commentRss': 'https://graylog.org/post/building-an-operations-dashboard/feed/',
      'slash:comments': 0,
      'media:content': {
        'media:title': {
          '#text': 'OPS Dashboard',
          attr_type: 'plain',
        },
        'media:thumbnail': {
          attr_url: 'https://graylog.org/wp-content/uploads/2023/06/Social-Image-ops-dashboard.png',
          attr_width: '150',
          attr_height: '79',
        },
        'media:copyright': 'Jeff Darrington',
        attr_url: 'https://graylog.org/wp-content/uploads/2023/06/Social-Image-ops-dashboard.png',
        attr_type: 'image/png',
        attr_medium: 'image',
        attr_width: '1200',
        attr_height: '628',
      },
    },
  ],
  isLoadingFeed: true,
  error: null,
};
jest.mock('components/content-stream/hook/useContentStream', () => jest.fn(() => useContentMock));

describe('<ContentStreamNews/>', () => {
  it('Show loading spinner', () => {
    render(<ContentStreamNews />);

    expect(screen.queryByText(useContentMock.feedList[0].title)).not.toBeInTheDocument();
  });

  it('Render ContentStream', async () => {
    asMock(useContentStream).mockReturnValue({ ...useContentMock, isLoadingFeed: false });
    render(<ContentStreamNews />);

    await screen.findByText(useContentMock.feedList[0].title);
  });
});
